﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace yysAuxiliary
{
    public class MouseHook
    {
        //use to judge doubleClick

        private int doubleClickcount = 0;
        private DateTime lastClickTime;
        private int pointx = -1;
        private int pointy = -1;


        int hHook;
        public bool IsHooking = false;

        Win32Api.HookProc MouseHookDelegate;

        /// <summary>
                /// mouse down event
                /// </summary>
        public event MouseEventHandler OnMouseDownEvents;
        /// <summary>
        /// mouse doubleclick event
        /// </summary>
        public event MouseEventHandler OnDoubleClickEvents;
        /// <summary>
        /// mouse up event
        /// </summary>
        public event MouseEventHandler OnMouseUpEvents;
        /// <summary>
        /// mouse move event
        /// </summary>
        public event MouseEventHandler OnMouseMove;

        [DllImport("user32.dll")]
        public static extern int GetDoubleClickTime();
        public MouseHook() { }
        ~MouseHook()
        {
            if (IsHooking)
            {
                Win32Api.UnhookWindowsHookEx(hHook);
            }
        }

        public bool SetHook()
        {

            MouseHookDelegate = new Win32Api.HookProc(MouseHookProc);

            Process cProcess = Process.GetCurrentProcess();

            ProcessModule cModule = cProcess.MainModule;

            var mh = Win32Api.GetModuleHandle(cModule.ModuleName);

            hHook = Win32Api.SetWindowsHookEx(Win32Api.WH_MOUSE_LL, MouseHookDelegate, mh, 0);

            if (hHook == 0)
                return false;
            IsHooking = true;
            return true;
        }

        public void UnHook()
        {
            if (IsHooking)
            {
                if (Win32Api.UnhookWindowsHookEx(hHook))
                {
                    IsHooking = false;
                }
            }
        }

        private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            //if (nCode != 0)
            //{

            //}
            MouseButtons button = MouseButtons.None;
            int delta = 0;
            int clickCount = 0;
            switch (wParam)
            {
                case Win32Api.WM_LBUTTONDOWN:
                    button = MouseButtons.Left;
                    clickCount = 1;
                    delta = 1;
                    break;
                case Win32Api.WM_LBUTTONUP:
                    button = MouseButtons.Left;
                    clickCount = 1;
                    delta = 2;
                    break;
                case Win32Api.WM_LBUTTONDBLCLK:
                    button = MouseButtons.Left;
                    clickCount = 2;
                    delta = 1;
                    break;
                case Win32Api.WM_RBUTTONDOWN:
                    button = MouseButtons.Right;
                    clickCount = 1;
                    delta = 1;
                    break;
                case Win32Api.WM_RBUTTONUP:
                    button = MouseButtons.Right;
                    clickCount = 1;
                    delta = 2;
                    break;
                case Win32Api.WM_RBUTTONDBLCLK:
                    button = MouseButtons.Right;
                    clickCount = 2;
                    delta = 1;
                    break;
                case Win32Api.WM_MBUTTONDOWN:
                    button = MouseButtons.Middle;
                    clickCount = 1;
                    delta = 1;
                    break;
                case Win32Api.WM_MBUTTONUP:
                    clickCount = 1;
                    delta = 2;
                    break;
                case Win32Api.WM_MBUTTONDBLCLK:
                    button = MouseButtons.Middle;
                    clickCount = 2;
                    delta = 1;
                    break;
            }

            //delta = 1 when mouse down ,delta = 2 when mouse up

            //Do MouseDown Events
            if (wParam == Win32Api.WM_LBUTTONDOWN || wParam == Win32Api.WM_RBUTTONDOWN || wParam == Win32Api.WM_MBUTTONDOWN)
            {
                //get mouse callback info
                Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct));
                MouseEventArgs e;
                System.TimeSpan clickTimeSpan = DateTime.Now - lastClickTime;
                lastClickTime = DateTime.Now;
                if (clickTimeSpan.TotalMilliseconds <= GetDoubleClickTime() && wParam == Win32Api.WM_LBUTTONDOWN && MyMouseHookStruct.pt.x == pointx && MyMouseHookStruct.pt.y == pointy)
                {
                    doubleClickcount++;
                }
                else
                {
                    doubleClickcount = 1;
                }
                pointx = MyMouseHookStruct.pt.x;
                pointy = MyMouseHookStruct.pt.y;
                if (doubleClickcount == 1)
                {
                    if (OnMouseDownEvents != null)
                    {
                        e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, delta);
                        OnMouseDownEvents(this, e);
                    }
                }

                if (doubleClickcount == 2)
                {
                    if (OnDoubleClickEvents != null)
                    {
                        e = new MouseEventArgs(button, doubleClickcount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, delta);
                        doubleClickcount = 0;
                        OnDoubleClickEvents(this, e);
                    }
                }
            }

            //Do MouseUp Events
            if (wParam == Win32Api.WM_LBUTTONUP || wParam == Win32Api.WM_MBUTTONUP || wParam == Win32Api.WM_RBUTTONUP)
            {
                //get mouse callback info
                Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct));
                MouseEventArgs e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, delta);
                //check is registed events
                if (OnMouseUpEvents != null)
                {
                    OnMouseUpEvents(this, e);
                }
            }

            if (wParam == Win32Api.WM_MOUSEMOVE)
            {
                //get mouse callback info
                Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct));

                MouseEventArgs e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, delta);

                if (OnMouseMove != null)
                {
                    OnMouseMove(this, e);
                }
            }


            return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam);
        }
    }
}
